<?php

include_once './Utils.php';
include_once './User.php';
include_once './MySQLConnect.php';
include_once 'PHPUnit/Framework/Assert/Functions.php';

// the db connection config file for testing purposes
define('TEST_DB_CONFIG_FILE', './test_db_config.php');

if(file_exists(TEST_DB_CONFIG_FILE)) {
    echo "\nTest config file found at '" . TEST_DB_CONFIG_FILE . "'!\n";
    
    include_once TEST_DB_CONFIG_FILE;
}
else {
    echo "\nTest config file not found, the default config will be used!\n";

    // default connection configuration
    define('MYSQL_HOST', '127.0.0.1:3306'); // localhost doesn't work, use 127.0.0.1 !!!
    define('MYSQL_USER', 'root');
    define('MYSQL_PASS', '');
    define('MYSQL_DB', 'emmerichgn_situare_test');
}


/**
 * PHPUnit test for class MySQLConnect.
 *
 * @author lacci
 */
class MySQLConnectTest extends PHPUnit_Framework_TestCase {   
    private static $testUsers = NULL;

    public static function setUpBeforeClass() {
        parent::setUpBeforeClass();
        
        try {
            MySQLConnect::setConnectionConfig(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB);

            self::$testUsers = array(
                new User(1, "First1 Last1", 'http://images.facebook.com/profile/1'),
                new User(2, "First2 Last2", 'http://images.facebook.com/profile/2'),
                new User(3, "First3 Last3", 'http://images.facebook.com/profile/3'),
                new User(4, "First4 Last4", 'http://images.facebook.com/profile/4'),
                new User(5, "First5 Last5", 'http://images.facebook.com/profile/5')
            );
        }
        catch (Exception $e) {
            echo $e->getTraceAsString();
            self::fail("Exception: " . $e->getCode() . "] " . $e->getMessage());
        }

        self::clearAllTables();
    }

    protected static function clearAllTables() {
        // clear the 'user' table
        self::clearTable('user');
        assertEquals(0, count(MySQLConnect::executeSelect("SELECT * FROM `user`;")));

        // clear the 'friend' table
        self::clearTable('friend');
        assertEquals(0, count(MySQLConnect::executeSelect("SELECT * FROM `friend`;")));

        // clear the 'location' table
        self::clearTable('location');
        assertEquals(0, count(MySQLConnect::executeSelect("SELECT * FROM `location`;")));
    }

    protected static function clearTable($tableName) {
        if (!$mysqli = mysqli_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB)) {
            self::fail("Can't connect to DB to clear the table '$tableName'");
        }

        $result = mysqli_query($mysqli, "TRUNCATE TABLE `$tableName`;");

        assertTrue($result, "Can't clear the table '$tableName'! DBError: [" . mysqli_errno($mysqli) . "] " . mysqli_error($mysqli));

        mysqli_close($mysqli);
    }

    /**
     * Helper method which returns the array of UID
     * of the Users passed in the input array.
     *
     * @param array $userArray array of User objects
     * @return array array of UIDs
     */
    protected static function getUserUIDs($userArray) {
        $resultArray = array();

        foreach ($userArray as $user) {
            $resultArray[] = $user->getUid();
        }

        return $resultArray;
    }

    public function testUsers() {
        // insert array of users
        $insertedUsersCount = MySQLConnect::insertUsers(self::$testUsers);
        // check the count of inserted users
        assertEquals(count(self::$testUsers), $insertedUsersCount, "Wrong number of inserted users!");
        assertEquals(count(self::$testUsers), count(MySQLConnect::executeSelect("SELECT * FROM `user`;")));

        // check the inserted users' data
        foreach (self::$testUsers as $user) {
            $uid = $user->getUid();
            $result = MySQLConnect::executeSelect("SELECT * FROM `user` WHERE `uid`=$uid;");
            assertEquals(1, count($result), "uid=$uid: Wrong count of found records!");
            assertEquals($user->getUid(), $result[0]['uid'], "uid=$uid: Wrong UID!");
            assertEquals($user->getName(), $result[0]['name'], "uid=$uid: Wrong name!");
            assertEquals($user->getProfilePhotoURL(), $result[0]['pic_square'], "uid=$uid: Wrong pic_square!");
            assertEquals($user->getExtraData('pic_big'), $result[0]['pic_big'], "uid=$uid: Wrong pic_big!");
        }

        // create friendships
        MySQLConnect::insertFriends(1, array(2,3));
        MySQLConnect::insertFriends(2, array(1,3));
        MySQLConnect::insertFriends(3, array(1,4,5));
        MySQLConnect::insertFriends(4, array(5));

//        MySQLConnect::executeSelect("CALL get_locations(1);");
        
        $data = MySQLConnect::getAllLocations(1);
        // user 1 has 2 friends: 2 and 3
        assertEquals(3, count($data), "Wrong number of found records!");
        foreach ($data  as $row) {
            assertContains($row['uid'], array(1,2,3), "UID invalid!");
        }

        $data = MySQLConnect::getAllLocations(2);
        // user 2 has 2 friends: 1 and 3
        assertEquals(3, count($data), "Wrong number of found records!");
        foreach ($data  as $row) {
            assertContains($row['uid'], array(1,2,3), "UID invalid!");
        }

        $data = MySQLConnect::getAllLocations(3);
        // user 3 has 3 friends: 1,2,4 and 5
        assertEquals(5, count($data), "Wrong number of found records!");
        foreach ($data  as $row) {
            assertContains($row['uid'], array(1,2,3,4,5), "UID invalid!");
        }

        $data = MySQLConnect::getAllLocations(4);
        // user 4 has 2 friends: 3 and 5
        assertEquals(3, count($data), "Wrong number of found records!");
        foreach ($data  as $row) {
            assertContains($row['uid'], array(3,4,5), "UID invalid!");
        }

        $data = MySQLConnect::getAllLocations(5);
        // user 5 has 2 friends: 4 and 3
        assertEquals(3, count($data), "Wrong number of found records!");
        foreach ($data  as $row) {
            assertContains($row['uid'], array(5,4,3), "UID invalid!");
        }

        // ////////////////////////
        // update outdated user
        //

        $count = MySQLConnect::executeInsertOrUpdateOrDelete("UPDATE `user` SET `update`=TRUE WHERE `uid`=5");
        assertEquals(1, $count, "Wrong number of updated users marked as outdated!");


        $allUsers = array();
        foreach (self::$testUsers as $user) {
            $allUsers[$user->getUid()] = $user;
        }
        $outdatedUsers = MySQLConnect::filterOutdatedUsers($allUsers);
        assertEquals(1, count($outdatedUsers));
        assertNotNull($outdatedUsers[5]);
        assertEquals(5, $outdatedUsers[5]->getUid());

        // --------

        $count = MySQLConnect::executeInsertOrUpdateOrDelete("UPDATE `user` SET `update`=TRUE WHERE `uid`=1");
        assertEquals(1, $count, "Wrong number of updated users marked as outdated!");

        // friend '2' removed, friend '4' added
        MySQLConnect::updateFriends(1, array(2,3), array(3,4));
        // check the current status
        $data = MySQLConnect::getAllLocations(1);
        // user 1 has 2 friends: 3 and 4
        assertEquals(3, count($data), "Wrong number of found records!");
        foreach ($data  as $row) {
            assertContains($row['uid'], array(1,3,4), "UID invalid!");
        }



    }

    public function testLocations() {
        //////////
        // set up the db test data
        self::clearAllTables();
        // insert array of users
        $insertedUsersCount = MySQLConnect::insertUsers(self::$testUsers);
        // check the count of inserted users
        assertEquals(count(self::$testUsers), $insertedUsersCount, "Wrong number of inserted users!");
        assertEquals(count(self::$testUsers), count(MySQLConnect::executeSelect("SELECT * FROM `user`;")));
        // create friendships
        MySQLConnect::insertFriends(1, array(2,3));
        MySQLConnect::insertFriends(2, array(1,3));
        MySQLConnect::insertFriends(3, array(1,4,5));
        MySQLConnect::insertFriends(4, array(5));


        self::$testUsers[0]->setLocation(new Location(55.555, 77.777, 123456, "old location", "old address"));
        MySQLConnect::insertLocations(self::$testUsers);
        MySQLConnect::insertLocation(1, 11.45, 34.234, "A test address", "I'm here");
        MySQLConnect::insertLocation(3, 23.67, 24.777, "A test address for user No.3", "My location");
        // distance between (11.45, 34.234) and (23.67, 24.777) is

        // from the point of view the user uid=1
        $result = MySQLConnect::getAllLocations(1);
        assertEquals(3, count($result));        
        foreach ($result as $datarow) {
            if ($datarow['uid']==1) {
                assertEquals(0, $datarow['distance']);
                assertEquals(11.45, $datarow['lon']);
                assertEquals(34.234, $datarow['lat']);
                assertEquals("A test address", $datarow['address']);
                assertEquals("I'm here", $datarow['note']);
            }
            else if ($datarow['uid']==2) {
                assertEquals(NULL, $datarow['distance']);
                assertEquals(NULL, $datarow['lon']);
                assertEquals(NULL, $datarow['lat']);
                assertEquals(NULL, $datarow['address']);
                assertEquals(NULL, $datarow['note']);
            }
            else if ($datarow['uid']==3) {
                assertEquals(1580, intval($datarow['distance']));
                assertEquals(23.67, $datarow['lon']);
                assertEquals(24.777, $datarow['lat']);
                assertEquals("A test address for user No.3", $datarow['address']);
                assertEquals("My location", $datarow['note']);
            }
            else {
                $this->fail("Unexpected UID in result! uid=" . $datarow['uid']);
            }
        }        
    }

}
?>
